package com.transfer.http.download.taskInterface;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.transfer.common.SuspendInterface;
import com.transfer.conf.FileTransferConfiguration;

public class FileSliceDownloadTask implements Runnable,SuspendInterface {
  private static final Logger log = LoggerFactory.getLogger(FileSliceDownloadTask.class);
  public static final int STATUS_HASNOT_FINISHED = 0;// 子任务没有完成
  public static final int STATUS_HAS_FINISHED = 1;// 子任务已经完成
  public static final int STATUS_HTTPSTATUS_ERROR = 2;// 子任务的http状态
  private FileDownloadTask task;
  private int id;
  private long startPos;
  private long endPos;
  private int downloadBufferSize;
  private long flushSize;
  private int maxRetry;
  private final CountDownLatch latch;
  private File tempFile = null;

  private volatile boolean shutdownRequested = false;
  private int status = FileSliceDownloadTask.STATUS_HASNOT_FINISHED;

  public FileSliceDownloadTask(FileDownloadTask task, CountDownLatch latch, int id, long startPos,
      long endPos) {
    super();
    this.task = task;
    this.id = id;
    this.startPos = startPos;
    this.endPos = endPos;
    this.latch = latch;
    setTempFile(new File(this.task.getFileStorageDir() + this.task.fileName + "_" + id));
    if (!getTempFile().exists()) {
      try {
        getTempFile().createNewFile();
      } catch (IOException e) {
        log.info("文件传输任务id：" + this.task.getTaskId() + " 创建文件失败：" + e);
      }
    }
  }

  public void run() {
    init();
    daTask();
  }

  public void init() {
    this.downloadBufferSize = FileTransferConfiguration.downloadBufferSize;
    this.flushSize = FileTransferConfiguration.flushSize;
    this.maxRetry = FileTransferConfiguration.maxRetry;
  }

  public void daTask() {
    log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id);
    HttpURLConnection con = null;
    InputStream inputStream = null;
    BufferedOutputStream outputStream = null;
    long downloadedFileLen = 0;
    long threadDownloadLength = endPos - startPos;

    try {
      outputStream = new BufferedOutputStream(new FileOutputStream(getTempFile().getPath(), true));
    } catch (FileNotFoundException e2) {
      log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id + " 文件不存在： " + e2);
    }

    int tmpRetry = 0;
    while (!shutdownRequested) {
      try {
        con = (HttpURLConnection) task.getDownloadURL().openConnection();
        setHeader(con);
        con.setAllowUserInteraction(true);
        con.setConnectTimeout(10000);
        con.setReadTimeout(10000);

        System.out.println("endPos: " + endPos);
        if (startPos >= endPos) {
          status = FileSliceDownloadTask.STATUS_HAS_FINISHED;
        } else {// 还有数据需要下载
          con.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos);
          log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id
              + " startPosition is " + startPos + "; endPosition is " + endPos);
          // 如果出现错误
          if (con.getResponseCode() != HttpURLConnection.HTTP_OK
              && con.getResponseCode() != HttpURLConnection.HTTP_PARTIAL) {
            log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id + ": code = "
                + con.getResponseCode() + ", status = " + con.getResponseMessage());
            status = FileSliceDownloadTask.STATUS_HTTPSTATUS_ERROR;
            this.task.setStatusError(true);
            log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id
                + " has a error, and is terminated!");
            latch.countDown();// 任务子线程有一个结束
            break;
          }
          // 没有出现错误
          inputStream = con.getInputStream();
          int len = 0;
          byte[] b = new byte[this.downloadBufferSize];
          System.out.println("downloadBufferSize: " + downloadBufferSize);
          while (!shutdownRequested && !this.task.isStatusError()
              && (len = inputStream.read(b)) != -1) {
            outputStream.write(b, 0, len);
            downloadedFileLen += len;
            startPos += len;
            if (downloadedFileLen % this.flushSize == 0) {
              flushOutputStream(outputStream);// 每隔一定size将流中数据flush到磁盘
            }
          }
          flushOutputStream(outputStream);// 将流中数据flush到磁盘
          if (downloadedFileLen >= threadDownloadLength) {
            status = FileSliceDownloadTask.STATUS_HAS_FINISHED;
          }
        }
        log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id
            + " sucess and finished!");
        latch.countDown();
        break;
      } catch (IOException e) {
        log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id + "发生异常: " + e);
        flushOutputStream(outputStream);
        sleep(e);
        tmpRetry++;
        if (tmpRetry >= this.maxRetry) {
          log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id + "重试超过最大重试次数！");
          break;
        }
        clearBeforeTaskFinish(inputStream, outputStream, con);
      }
    }
    clearBeforeTaskFinish(inputStream, outputStream, con);
  }

  private void flushOutputStream(BufferedOutputStream outputStream) {
    try {
      outputStream.flush();
    } catch (IOException e3) {
      log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id + " ,将数据flush到磁盘时发生异常:"
          + e3);
    }
  }

  private void sleep(IOException e) {
    try {
      TimeUnit.SECONDS.sleep(this.task.getSleepSeconds());
    } catch (InterruptedException e3) {
      log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id + "发生异常: " + e
          + " ，并且线程睡眠时发生异常:" + e3);
    }
  }

  private void clearBeforeTaskFinish(InputStream inputStream, BufferedOutputStream outputStream,
      HttpURLConnection con) {
    closeInputStream(inputStream);
    closeOutputStream(outputStream);
    con.disconnect();
  }

  private void closeInputStream(InputStream inputStream) {
    if (inputStream != null) {
      try {
        inputStream.close();
      } catch (IOException e) {
        log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id
            + "关闭inputStream流时发生异常: " + e);
      }
    }
  }

  private void closeOutputStream(BufferedOutputStream outputStream) {
    if (outputStream != null) {
      try {
        outputStream.close();
      } catch (IOException e) {
        log.info("文件传输任务id：" + this.task.getTaskId() + " ,子线程id： " + this.id
            + "关闭outputStream流时发生异常: " + e);
      }
    }
  }

  /*
   * private void setHeader(URLConnection con) { con.setRequestProperty("Accept-Language",
   * "en-us,en;q=0.7,zh-cn;q=0.3"); con.setRequestProperty("Accept-Charset",
   * "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); con.setRequestProperty("Keep-Alive", "300");
   * con.setRequestProperty("Connection", "keep-alive"); }
   */
  private void setHeader(URLConnection con) {
    con.setRequestProperty(
        "User-Agent",
        "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092510 Ubuntu/8.04 (hardy) Firefox/3.0.3");
    con.setRequestProperty("Accept-Language", "en-us,en;q=0.7,zh-cn;q=0.3");
    con.setRequestProperty("Accept-Encoding", "aa");
    con.setRequestProperty("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
    con.setRequestProperty("Keep-Alive", "300");
    con.setRequestProperty("Connection", "keep-alive");
    con.setRequestProperty("If-Modified-Since", "Fri, 02 Jan 2009 17:00:05 GMT");
    con.setRequestProperty("If-None-Match", "\"1261d8-4290-df64d224\"");
    con.setRequestProperty("Cache-Control", "max-age=0");
    con.setRequestProperty("Referer", "http://www.skycn.com/soft/14857.html");
  }

  public void shutdownRequest() {
    shutdownRequested = true;
  }

  public File getTempFile() {
    return tempFile;
  }

  public void setTempFile(File tempFile) {
    this.tempFile = tempFile;
  }

  public FileDownloadTask getTask() {
    return task;
  }

  public void setTask(FileDownloadTask task) {
    this.task = task;
  }

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public long getStartPos() {
    return startPos;
  }

  public void setStartPos(long startPos) {
    this.startPos = startPos;
  }

  public long getEndPos() {
    return endPos;
  }

  public void setEndPos(long endPos) {
    this.endPos = endPos;
  }

  public int getStatus() {
    return status;
  }

  public void setStatus(int status) {
    this.status = status;
  }
}
